package com.wyg.lambda.methodref.objectref;

import java.io.Closeable;
import java.io.IOException;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 *
 * 三、对象方法引用
 *
 * 使用前提条件:
 *      1.函数式接口的抽象法必须要有参数！
 *      2.函数式接口的抽象法-第一个参数必须为传入的对象(最好是自定义对象)，
 *      3.函数式接口的抽象法-后面的【所有参数】必须与传入对象调用的【方法参数】一致（无参数、或多参数）。
 *
 * 一下方法类型均不能使用，因为抽象方法都没有参数：
 *      Runnable r1 = () -> {};
 *      Closeable c1 = () -> {};
 *      Supplier<String> s1 = () -> "";
 *
 *
 * 抽象方法的第一个参数类型刚好是实例方法的类型，抽象方法剩余 的参数恰好可以当做实例方法的参数。
 * 如果函数式接口的实现能由上面说的实例方法调用来实现的话，那么就可以使用对象方法引用。
 *
 * 方法引用-表达式：
 *          类名::instMethod   【仅仅表示引用，所以不需要instMethod方法名后面加()】
 *
 * 对应普通Lambda-表达式：
 *          (inst,args) -> 类名.instMethod(args)
 *
 *
 * @ClassName: ObjectRef
 * @Auther: WangYG
 * @Date: 2020-02-21 23:28:19
 * @Version: 1.0
 */
public class ObjectRef {


    /**
     * 功能描述: 抽象方法都没有参数，无法使用-对象方法引用的 演示
     * @methodName: notUsed
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-21 23:40:48
     */
    private void notUsed(){
        Runnable r1 = () -> {};
        Closeable c1 = () -> {};
        Supplier<String> s1 = () -> "";

        new Closeable(){
            @Override
            public void close() throws IOException {

            }
        };

        new Runnable(){
            @Override
            public void run() {
            }
        };

    }

    /**
     * 功能描述: 演示简单的Lambda表示式-对象方法引用示例-一个对象参数（对象调用的抽象方法无参数）的演示
     * @methodName: one
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-21 23:51:54
     */
    public void one(){
        Too too = new Too();
        //1.普通方式Lambda表达式
        Consumer<Too> c1 = (Too t) -> new Too().sayHi();
        Consumer<Too> c2 = (Too t) -> t.sayHi();
        System.out.print("this is ObjectRef one() c1 : ");
        c1.accept(too);
        System.out.print("this is ObjectRef one() c2 : ");
        c1.accept(too);
        //2.Lambda表达式-对象方法引用-示例
        Consumer<Too> c3 = Too::sayHi;
        System.out.print("this is ObjectRef one() Fun Lambda-ObjectRef c3 : ");
        c3.accept(too);
    }

    /**
     * 功能描述: 演示简单的Lambda表示式-对象方法引用示例-一个对象参数 和 一个被调用方法的参数 的演示
     * @methodName: two
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-22 00:23:49
     */
    public void two(){

        Too too = new Too();
        //1.普通方式Lambda表达式
        BiConsumer<Too,String> bc1 = (Too t,String name) -> new Too().sayName(name);
        BiConsumer<Too,String> bc2 = (t,name) -> t.sayName(name);
        System.out.print("this is ObjectRef two() bc1 : ");
        bc1.accept(too,"张三1");
        System.out.print("this is ObjectRef two() bc2 : ");
        bc2.accept(too,"张三2");
        //2.Lambda表达式-对象方法引用-示例
        BiConsumer<Too,String> bc3 = Too::sayName;
        System.out.print("this is ObjectRef two() Fun Lambda-ObjectRef bc3 : ");
        bc3.accept(too,"李四");
    }

    /**
     * 功能描述: 演示简单的Lambda表示式-对象方法引用示例-一个对象参数 和 一个被调用方法的参数 并且有一个返回值 的演示
     * @methodName: three
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-22 00:32:21
     */
    public void three(){

        Too too = new Too();

        //1.普通方式Lambda表达式
        BiFunction<Too,String,String> bf1 = (Too t,String code) -> {return new Too().toUpperCase(code);};
        BiFunction<Too,String,String> bf2 = (t,code) -> t.toUpperCase(code);
        System.out.println("this is ObjectRef three() Fun bf1 : " + bf1.apply(too,"lambda"));
        System.out.println("this is ObjectRef three() Fun bf2 : " + bf2.apply(too,"lambda"));

        //2.Lambda表达式-对象方法引用-示例
        BiFunction<Too,String,String> bf3 = Too::toUpperCase;
        System.out.println("this is ObjectRef three() Fun Lambda-ObjectRef bf3 : " + bf3.apply(too,"lambda-instanceRef"));
    }

    /**
     * 功能描述: 演示简单的Lambda表示式-对象方法引用示例-自定义函数式接口调用Lambda对象方法引用。
     * <p>
     *     自定义接口interface IToo<T,U,K,R>，有且仅有一个抽象方法public R runSum(T too,U a,K b);
     *     演示：1个对象，2个方法参数，1个返回值的实例
     * </p>
     * @methodName: four
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-22 00:47:00
     */
    public void four(){

        Too too = new Too();
        //1.普通方式Lambda表达式
        IToo<Too,Integer,Integer,Integer> it1 = (Too t,Integer a,Integer b) -> {return new Too().sum(a,b);};
        IToo<Too,Integer,Integer,Integer> it2 = (t,a,b) -> t.sum(a,b);
        System.out.println("this is ObjectRef four() Fun it1 : " + it1.runSum(too,5,5));
        System.out.println("this is ObjectRef four() Fun it2 : " + it2.runSum(too,15,5));
        //2.Lambda表达式-对象方法引用-示例
        IToo<Too,Integer,Integer,Integer> it3 = Too::sum;
        System.out.println("this is ObjectRef four() Fun Lambda-ObjectRef it3 : " + it3.runSum(too,100,100));
    }


}

class Too{

    public void sayHi(){
        System.out.println("Hello! this is Too sayHi().");
    }

    public void sayName(String name){
        System.out.println("hello, my name is : " + name);
    }

    public String toUpperCase(String code){
        return code.toUpperCase();
    }

    public int sum(int a, int b){
        return a+b;
    }

}

interface IToo<T,U,K,R>{

    public R runSum(T too,U a,K b);

}
